home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Technology Seed / ADC Seed CD - July 1999.toast / Carbon SDK 1.0d10c3 / Sample Code / AppearanceSample / AppearanceSampleMain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-01  |  41.2 KB  |  1,569 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        AppearanceSampleMain.c
  3.  
  4.     Contains:    Main application code for our sample app.
  5.  
  6.     Version:    Appearance 1.0 SDK
  7.  
  8.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Edward Voas
  13.  
  14.         Other Contact:        7 of 9, Borg Collective
  15.  
  16.         Technology:            OS Technologies Group
  17.  
  18.     Writers:
  19.  
  20.         (jss)    Jeff Shulman
  21.         (MAA)    Matt Ackeret
  22.         (edv)    Ed Voas
  23.  
  24.     Change History (most recent first):
  25.  
  26.       <1.18>     4/19/99    jss        Added help tags from balloons
  27.       <1.17>     4/16/99    jss        BUILD_FOR_CARBON_8 -> BUILDING_FOR_CARBON_8
  28.     $Log: AppearanceSampleMain.c,v $
  29.     Revision 1.19  1999/04/29 20:51:25  voas
  30.     Use HELP_TAGS_ENABLED to turn help stuff on.
  31.     
  32.     Revision 1.18  1999/04/19 21:24:47  kilroy
  33.     Added help tags from balloons
  34.     
  35.     Revision 1.17  1999/04/16 23:16:01  kilroy
  36.     BUILD_FOR_CARBON_8 -> BUILDING_FOR_CARBON_8
  37.     
  38.     Revision 1.16  1999/04/15 00:39:20  mattack
  39.     guyf edited the sources so they'd build on 8 and X while menu stuff was
  40.     in flux.
  41.     
  42.  
  43.       <1.15>      4/8/99    jss        GetMenuHandle, duh!
  44.       <1.14>      4/7/99    jss        Add help tag stuff
  45.         <12>      6/8/98    MAA        Fix upper limit in DoCursorMenu
  46.         <11>      5/4/98    MAA        Change DoDialogTimeouts to use an actual DLOG resource.. using
  47.                                     ParamText to do the substitution in StandardAlert doesn't work.
  48.         <10>     3/16/98    MAA        Use EnableMenuItem/DisableMenuItem instead of the older calls
  49.          <9>      3/2/98    MAA        There's temporary commented out code in SetupUpModifiersMenu to
  50.                                     test xmnu vs. programmatic setting of keyboard glyphs
  51.          <8>     2/18/98    MAA        remove protos for menu bar accessors
  52.          <7>     1/22/98    MAA        Add ProxyPath dialog support
  53.          <6>     1/12/98    MAA        Add menu hide/show menu item code, and disabled dialog timeout
  54.                                     code.  (Will renable when I get a new library.)
  55.          <5>    12/18/97    MAA        Fix glyph in SetupModifiersMenu
  56.          <4>    10/29/97    MAA        Put the font menu into a global so we can disable it when
  57.                                     CDEFTester goes away.
  58.          <3>    10/28/97    MAA        Add Font menu back in, fix a bug in SetUpFontMenu
  59.          <2>    10/28/97    edv        Use RadioGroup control!
  60.          <1>     9/11/97    edv        First checked in.
  61. */
  62.  
  63.  
  64. //
  65. //    This program is actually based on the skeleton code from Scott Knaster's
  66. //    Macintosh Programming Secrets book. So, if you're looking at this code,
  67. //    Scott, it may look slightly familiar.
  68. //
  69.  
  70. #include "AppearanceSamplePrefix.h"
  71.  
  72. #include <Events.h>
  73. #include <MacTypes.h>
  74. #include <Files.h>
  75. #include <Gestalt.h>
  76. #include <Processes.h>
  77. #include <Movies.h>
  78. #include <Menus.h>
  79. #include <Fonts.h>
  80. #include <DiskInit.h>
  81. #include <Devices.h>
  82. #include <TextUtils.h>
  83. #include <Resources.h>
  84. #include <Appearance.h>
  85.  
  86. #include "FinderWindow.h"
  87. #include "DialogWindow.h"
  88. #include "BevelDialog.h"
  89. #include "BevelImageAPIWindow.h"
  90. #include "CDEFTester.h"
  91. #include "LiveFeedbackDialog.h"
  92. #include "MegaDialog.h"
  93. #include "UtilityWindow.h"
  94. #include "SideUtilityWindow.h"
  95. #include "MenuDrawing.h"
  96. #include "ProxyDialog.h"
  97.  
  98. #define topLeft(r)    (((Point *) &(r))[0])
  99. #define botRight(r)    (((Point *) &(r))[1])
  100.  
  101. /* ==================================================================================*/
  102. /* ======================= R E S O U R C E   N U M B E R S ==========================*/
  103. /* ==================================================================================*/
  104.  
  105. enum
  106. {
  107.     kAlertStartupError        = 129
  108. };
  109.  
  110. enum
  111. {
  112.     kErrorStrings            = 128,
  113.     kWeirdSystemString        = 1,
  114.     kNoAppearanceString        = 2,
  115.     kResourceMissingString    = 3
  116. };
  117.  
  118. enum
  119. {
  120.     kAboutBoxDialogID        = 5000
  121. };
  122.  
  123. #define kObjectWindowKind        2000
  124.  
  125. /*     The following constants are used to identify menus and their items. The menu IDs
  126.     have an "m" prefix and the item numbers within each menu have an "i" prefix. */
  127.  
  128. enum
  129. {
  130.     rMenuBar                = 128                /* application's menu bar */
  131. };
  132.  
  133. enum
  134. {
  135.     mApple                    = 128,                /* Apple menu */
  136.     iAbout                    = 1
  137. };
  138.  
  139. enum
  140. {
  141.     mFile                    = 129,                /* File menu */
  142.     iClose                    = 1,
  143.     iQuit                    = 3
  144. };
  145.  
  146. enum
  147. {
  148.     mExamples                = 130,
  149.     iFinderWindow            = 1,
  150.     iDialogWindow            = 2,
  151.     iBevelDialog            = 3,
  152.     iNewThemeDialog            = 4,
  153.     iStandardAlert            = 5,
  154.     iBevelButtonContent        = 6,
  155.     iCDEFTester                = 7,
  156.     iLiveFeedbackDialog        = 8,
  157.     iMegaDialog                = 9,
  158.     iUtilityWindow            = 10,
  159.     iSideUtilityWindow        = 11,
  160.     iAutoSizeDialog            = 12,
  161.     iVerticalZoom            = 13,
  162.     iHorizontalZoom            = 14,
  163.     iProxyPathDialog        = 15
  164. };
  165.  
  166. enum
  167. {
  168.     mTestAPI                = 148,
  169.     iMenuDrawing            = 1,
  170.     iDumpControlHierarchy    = 2,
  171.     iHideMenu                = 3,
  172.     iDialogTimeouts            = 4
  173. };
  174.  
  175. enum
  176. {
  177.     kHorizZoomKind            = 128,
  178.     kVertZoomKind            = 129
  179. };
  180.  
  181. enum
  182. {
  183.     kMenuModifiers                = 145,
  184.     kNoModifiersItem            = 1,
  185.     kShiftModifierItem            = 2,
  186.     kShiftOptionModifierItem    = 3,
  187.     kShiftOptCntlModifierItem    = 4,
  188.     kCommandDeleteItem            = 5,
  189.     kIconSuiteItem                = 6
  190. };
  191.  
  192. enum
  193. {
  194.     kAboutSampleCmd            = 'abou',
  195.     kCloseCmd                = 'clos',
  196.     kQuitCmd                = 'quit',
  197.     kOpenFinderWindowCmd    = 'opfw',
  198.     kOpenDialogWindowCmd    = 'opdw',
  199.     kOpenBevelDialogCmd        = 'opbd',
  200.     kNewFeaturesDialogCmd    = 'newf',
  201.     kStandardAlertCmd        = 'stal',
  202.     kBevelImageAPICmd        = 'bvli',
  203.     kCDEFTesterCmd            = 'cdef',
  204.     kLiveFeedbackCmd        = 'live',
  205.     kUtilityWindowCmd        = 'util',
  206.     kSideUtilityWindowCmd    = 'side',
  207.     kMegaDialogCmd            = 'mega',
  208.     kAutoSizeCmd            = 'asiz',
  209.     kVerticalZoomCmd        = 'vert',
  210.     kHorizontalZoomCmd        = 'horz',
  211.     kProxyPathDialogCmd        = 'prox'
  212. };
  213.  
  214. enum
  215. {
  216.     kMenuTestAPI            = 148,
  217.     kMenuDrawingTest        = 'mdra',
  218.     kDumpHierarchy            = 'dhie',
  219.     kHideMenu                = 'hmen',
  220.     kDialogTimeouts            = 'dtim'
  221. };
  222.  
  223. enum
  224. {    
  225.     kMenuCursors                    = 149
  226. };
  227.     
  228.  
  229. //——————————————————————————————————————————————————————————————————————————————————
  230. //    Prototypes
  231. //——————————————————————————————————————————————————————————————————————————————————
  232.  
  233. static void        InitToolbox(void);
  234. static void        MainEventLoop(void);
  235.  
  236. /* Event handling routines */
  237.  
  238. static void        HandleEvent(EventRecord *event);
  239. static void        HandleActivate(EventRecord *event);
  240. static void        HandleDiskInsert(EventRecord *event);
  241. static void        HandleKeyPress(EventRecord *event);
  242. static void     HandleMouseDown(EventRecord *event);
  243. static void        HandleOSEvent(EventRecord *event);
  244. static void        HandleUpdate(EventRecord *event);
  245.  
  246. static void        AdjustMenus(void);
  247. static void        HandleMenuCommand(long menuResult);
  248.  
  249. /* Utility routines */
  250.  
  251. static void        CloseAnyWindow(WindowPtr window);
  252. static void        DeathAlert(short errorNumber);
  253. static Boolean    IsAppWindow(WindowPtr window);
  254. static Boolean     IsDAWindow(WindowPtr window);
  255. static Boolean    IsDialogWindow(WindowPtr window);
  256.  
  257. static Boolean    GetObjectFromWindow( WindowPtr window, BaseWindow** wind );
  258. static void        SetUpFontMenu();
  259. static void        SetUpModifiersMenu();
  260. static void        DoAboutBox();
  261.  
  262. static void        AutoSizeDialogTest();
  263. static void        SyncVertZoomRects( WindowPtr window );
  264. static void        SyncHorizZoomRects( WindowPtr window );
  265. static OSErr    GetReportFileSpec( FSSpecPtr file );
  266.  
  267. #if ENABLED_IN_CARBONLIB
  268. static pascal Boolean        TimeoutFilter(DialogPtr theDialog, EventRecord *theEvent, DialogItemIndex *itemHit);
  269. #endif
  270.  
  271. /* Custom Control Definition Stuff */
  272.  
  273. pascal SInt32 MyControlDefProc(    SInt16 varCode, ControlHandle theControl,
  274.     ControlDefProcMessage message, SInt32 param);
  275.  
  276. pascal OSStatus MyControlCNTLToCollectionProc( const Rect * bounds, SInt16 value,
  277.     Boolean visible, SInt16 max, SInt16 min, SInt16 procID, SInt32 refCon,
  278.     ConstStr255Param title, Collection collection);
  279.  
  280. /* External routines */
  281.  
  282. extern void        TestStandardAlert();
  283.  
  284. extern "C" WindowRef OpenDoc( short, FSSpec *, StringPtr );
  285.  
  286. //———————————————————————————————————————————————————————————————————————————
  287. //    Globals
  288. //———————————————————————————————————————————————————————————————————————————
  289.  
  290.  
  291. Boolean            gQuit;            /*     We set this to TRUE when the user selects
  292.                                     Quit from the File menu. Our main event loop
  293.                                     exits gQuit is TRUE. */
  294.  
  295. Boolean            gInBackground;    /*    gInBackground is maintained by our osEvent
  296.                                     handling routines. Any poart of the program
  297.                                     can check it to find out if it is currently
  298.                                     in the background. */
  299.  
  300. MenuHandle        gFontMenu = nil;        // Menu used to choose a font
  301.  
  302. #if ENABLED_IN_CARBONLIB
  303. Boolean            gAnimateCursor = false; 
  304. UInt32            gAnimationStep = 0;
  305. ThemeCursor        gWhichCursor;
  306. #endif 
  307.  
  308. //———————————————————————————————————————————————————————————————————————————
  309. //    Macros
  310. //———————————————————————————————————————————————————————————————————————————
  311.  
  312. #define    HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  313. #define    LoWrd(aLong)    ((aLong) & 0xFFFF)
  314.  
  315. //———————————————————————————————————————————————————————————————————————————
  316. //    • main
  317. //———————————————————————————————————————————————————————————————————————————
  318. //    Entry point for our program. We initialize the Toolbox, make sure we are
  319. //    running on a sufficiently brawny machine, and put up the menu bar. Finally,
  320. //    we start polling for events and handling then by entering our main event
  321. //    loop.
  322. //    
  323. int main( int /*argc*/, char** /*argv*/ )
  324. {
  325.     InitToolbox();                    /*    Initialize the program */
  326.  
  327.     new MegaDialog();                /*    Create our initial window */
  328.  
  329.     MainEventLoop();                    /*     Call the main event loop */
  330.  
  331.     return 0;
  332. }
  333.  
  334. //———————————————————————————————————————————————————————————————————————————
  335. //    • InitToolbox
  336. //———————————————————————————————————————————————————————————————————————————
  337. //    Set up the whole world, including global variables, Toolbox Managers, and
  338. //    menus.
  339. //    
  340. static void
  341. InitToolbox()
  342. {
  343.     SInt32                        result;
  344.     ControlDefSpec                defSpec;
  345.     Handle                        menuBar;
  346.     MenuHandle                    hierMenu;
  347.     OSErr                        err;
  348.     
  349.     gInBackground = false;
  350.     gQuit = false;
  351.  
  352.     InitCursor();
  353.  
  354.     // We have a custom control definition that we must
  355.     // register with the Control Manager so it can get called
  356.     // properly when it is used. We're registering this as
  357.     // 'CDEF' 500.
  358.  
  359.     defSpec.defType = kControlDefProcPtr;
  360.     defSpec.u.defProc = NewControlDefProc( MyControlDefProc );
  361.     RegisterControlDefinition( 500, &defSpec,
  362.         NewControlCNTLToCollectionProc( MyControlCNTLToCollectionProc ) );
  363.         
  364.     err = Gestalt( gestaltAppearanceAttr, &result );
  365.     if ( err )
  366.         DeathAlert( kNoAppearanceString );
  367.         
  368.     menuBar = GetNewMBar(rMenuBar);
  369.     if ( menuBar == nil )
  370.         DeathAlert( kResourceMissingString );
  371.     
  372.     // In order to get the theme-savvy menu bar, we need to call
  373.     // RegisterAppearanceClient.
  374.  
  375.     RegisterAppearanceClient();
  376.  
  377.     SetMenuBar(menuBar);
  378.  
  379.     hierMenu = GetMenu( kMenuCursors );
  380.     if (hierMenu)
  381.         InsertMenu(hierMenu, -1); // into the hierarchical portion of the menu list
  382.  
  383.     DisposeHandle(menuBar);
  384.     AppendResMenu(GetMenuHandle(mApple),'DRVR');
  385.     
  386.     SetUpFontMenu();
  387.  
  388.     SetUpModifiersMenu();
  389.     
  390.     AdjustMenus();
  391.  
  392. #if HELP_TAGS_ENABLED
  393.     // Set help for the File and Examples menus
  394.     {
  395.         HMHelpContentRec    menuTitleHelpContent;
  396.         
  397.         menuTitleHelpContent.version = kMacHelpVersion;
  398.         
  399.         ::SetRect( &menuTitleHelpContent.absHotRect, 0, 0, 0, 0 );        // Will be automatically filled in
  400.         
  401.         menuTitleHelpContent.tagSide = kHMDefaultSide;
  402.  
  403.         // Our minimum content is on a STR resource
  404.         menuTitleHelpContent.content[ kHMMinimumContentIndex ].contentType = kHMStrResContent;
  405.         menuTitleHelpContent.content[ kHMMinimumContentIndex ].u.tagStrRes = 130;
  406.  
  407.         // No maximum content
  408.         menuTitleHelpContent.content[ kHMMaximumContentIndex ].contentType = kHMNoContent;
  409.     
  410.         ::HMSetMenuItemHelpContent( GetMenuHandle( mExamples ), 0, &menuTitleHelpContent );
  411.         
  412.         // Use the 'hmnu' resource for the File menu
  413.         (void) ::HMSetMenuHelpFromBalloonRsrc( GetMenuHandle( mFile ), mFile );
  414.     }
  415. #endif    
  416.  
  417.     DrawMenuBar();
  418. }
  419.  
  420. //———————————————————————————————————————————————————————————————————————————
  421. //    • MainEventLoop
  422. //———————————————————————————————————————————————————————————————————————————
  423. //    Get events and handle them by calling HandleEvent. On every event, we call
  424. //    idle on the frontmost window, if there is one.
  425. //    
  426. static void
  427. MainEventLoop()
  428. {
  429.     RgnHandle        cursorRgn;
  430.     Boolean            gotEvent;
  431.     EventRecord        event;
  432.     WindowPtr        theWindow;
  433.     BaseWindow*        window;
  434.     
  435.     cursorRgn = nil;
  436.     while( !gQuit )
  437.     {
  438.         gotEvent = WaitNextEvent( everyEvent, &event, 60L, cursorRgn );
  439.         if ( gotEvent )
  440.         {
  441.             HandleEvent( &event );
  442.         }
  443. #if ENABLED_IN_CARBONLIB
  444.         else if (gAnimateCursor)
  445.         {
  446.             SetAnimatedThemeCursor(gWhichCursor,gAnimationStep);
  447.             gAnimationStep++;
  448.         }
  449. #endif         
  450.         
  451.         theWindow = FrontWindow();
  452.         if ( theWindow && GetObjectFromWindow( theWindow, &window ) )
  453.         {
  454.             window->Idle();            
  455.         }
  456.     }
  457. }
  458.  
  459. //———————————————————————————————————————————————————————————————————————————
  460. //    • HandleEvent
  461. //———————————————————————————————————————————————————————————————————————————
  462. //    Do the right thing for an event. Determine what kind of event it is and
  463. //    call the appropriate routines.
  464. //
  465. static void
  466. HandleEvent( EventRecord *event )
  467. {
  468.     switch ( event->what )
  469.     {
  470.         case mouseDown:
  471.             HandleMouseDown( event );
  472.             break;
  473.             
  474.         case keyDown:
  475.         case autoKey:
  476.             HandleKeyPress( event );
  477.             break;
  478.             
  479.         case activateEvt:
  480.             HandleActivate( event );
  481.             break;
  482.             
  483.         case updateEvt:
  484.             HandleUpdate( event );
  485.             break;
  486.             
  487.         case diskEvt:
  488.             HandleDiskInsert( event );
  489.             break;
  490.             
  491.         case osEvt:
  492.             HandleOSEvent( event );
  493.             break;
  494.     }
  495. }
  496.  
  497. //———————————————————————————————————————————————————————————————————————————
  498. //    • HandleActivate
  499. //———————————————————————————————————————————————————————————————————————————
  500. //    This is called when a window is activated or deactivated. In this sample,
  501. //    the Window Manager's handling of activate and deactivate events is
  502. //    sufficient. Others applications may have TextEdit records, controls, lists,
  503. //    etc., to activate/deactivate.
  504. //
  505. static void
  506. HandleActivate( EventRecord *event )
  507. {
  508.     WindowPtr        theWindow;
  509.     Boolean            becomingActive;
  510.     BaseWindow*        windObj;
  511.     
  512.     theWindow = (WindowPtr)event->message;
  513.     becomingActive = (event->modifiers & activeFlag) != 0;
  514.  
  515.     if ( IsDialogWindow( theWindow ) )
  516.     {
  517.         DialogRef        dialog;
  518.         SInt16            itemHit;
  519.  
  520.         DialogSelect( event, &dialog, &itemHit );
  521.     }
  522.     else if ( GetObjectFromWindow( theWindow, &windObj ) )
  523.     {
  524.         if ( becomingActive )
  525.             windObj->Activate( *event );
  526.         else
  527.             windObj->Deactivate( *event );
  528.     }
  529. }
  530.  
  531. //———————————————————————————————————————————————————————————————————————————
  532. //    • HandleDiskInsert
  533. //———————————————————————————————————————————————————————————————————————————
  534. //    Called when we get a disk-inserted event. Check the upper word of the
  535. //    event message; if it's nonzero, then a bad disk was inserted, and it
  536. //    needs to be formatted.
  537. //    
  538. static void
  539. HandleDiskInsert( EventRecord *event )
  540. {
  541.     Point        aPoint = {100, 100};
  542.     
  543.     if ( HiWrd( event->message ) != noErr )
  544.     {
  545.         DIBadMount( aPoint, event->message );
  546.     }
  547. }
  548.  
  549. //———————————————————————————————————————————————————————————————————————————
  550. //    • HandleKeyPress
  551. //———————————————————————————————————————————————————————————————————————————
  552. //    The user pressed a key, what are you going to do about it?
  553. //
  554. static void
  555. HandleKeyPress( EventRecord *event )
  556. {
  557.     char        key;
  558.     
  559.     key = event->message & charCodeMask;
  560.     if ( event->modifiers & cmdKey )
  561.     {
  562.         AdjustMenus();
  563.  
  564.         //**************************************************************************//
  565.         //    APPEARANCE ADOPTION ALERT!!                                                //
  566.         //**************************************************************************//
  567.         // Here we use the new MenuEvent routine instead of menu key. This allows
  568.         // us to handle extended modifier keys for the menu items that use them.
  569.         
  570.         HandleMenuCommand( MenuEvent( event ) );
  571.     }
  572.     else
  573.     {
  574.         WindowPtr     window = FrontWindow();
  575.         BaseWindow*    object;
  576.         
  577.         if ( window && GetObjectFromWindow( window, &object ) )
  578.         {
  579.             object->HandleKeyDown( *event );
  580.         }
  581.     }
  582. }
  583.  
  584. //———————————————————————————————————————————————————————————————————————————
  585. //    • HandleMouseDown
  586. //———————————————————————————————————————————————————————————————————————————
  587. //    Called to handle mouse clicks. The user could have clicked anywhere,so
  588. //    let's first find out where by calling FindWindow. That returns a number
  589. //    indicating where in the screen the mouse was clicked. "switch" on that
  590. //    number and call the appropriate routine.
  591. //
  592. static void
  593. HandleMouseDown( EventRecord *event )
  594. {
  595.     long        newSize;
  596.     Rect        growRect;
  597.     WindowPtr    theWindow;
  598.     short        part;
  599.     BitMap        screenBits;
  600.  
  601.     part = FindWindow( event->where, &theWindow );
  602.     
  603.     switch ( part )
  604.     {
  605.         case inMenuBar:
  606.             AdjustMenus();
  607.             HandleMenuCommand( MenuSelect( event->where ) );
  608.             break;
  609.             
  610.         case inSysWindow:
  611.             SystemClick( event, theWindow );
  612.             break;
  613.             
  614.         case inContent:
  615.             if ( theWindow != FrontWindow() )
  616.             {
  617.                 SelectWindow( theWindow );
  618.             }
  619.             else
  620.             {
  621.                 BaseWindow*     wind;
  622.                 
  623.                 if ( GetObjectFromWindow( theWindow, &wind ) )
  624.                     wind->HandleClick( *event );
  625.             }
  626.             break;
  627.             
  628.         case inDrag:
  629.             if ( GetWindowKind( theWindow ) != kObjectWindowKind )
  630.             {
  631.                 DragWindow( theWindow, event->where, &GetQDGlobalsScreenBits( &screenBits )->bounds );
  632.             }
  633.             else
  634.                 {
  635.                     BaseWindow*        wind;
  636.                     
  637.                     if ( GetObjectFromWindow( theWindow, &wind ) )
  638.                         wind->DoDragClick(event);
  639.                 }                
  640.                 
  641.             if ( GetWindowKind( theWindow ) == kHorizZoomKind )
  642.                 SyncHorizZoomRects( theWindow );
  643.             else if ( GetWindowKind( theWindow ) == kVertZoomKind )
  644.                 SyncVertZoomRects( theWindow );
  645.             break;
  646.             
  647.         case inGrow:
  648.             growRect = GetQDGlobalsScreenBits( &screenBits )->bounds;
  649.             growRect.top = growRect.left = 80;
  650.             newSize = GrowWindow(theWindow,event->where,&growRect);
  651.             if (newSize != 0)
  652.             {
  653.                 BaseWindow*        wind;
  654.                 
  655.                 if ( GetObjectFromWindow( theWindow, &wind ) )
  656.                     wind->Resize( LoWrd(newSize), HiWrd(newSize) );
  657.                 else
  658.                     SizeWindow( theWindow, LoWrd( newSize ), HiWrd( newSize ), true );
  659.             }
  660.             break;
  661.             
  662.         case inGoAway:
  663.             if (TrackGoAway(theWindow,event->where))
  664.                 CloseAnyWindow(theWindow);
  665.             break;
  666.  
  667.         case inProxyIcon:
  668. #if ENABLED_IN_CARBONLIB
  669.             HandleProxyDrag(theWindow, event);
  670. #endif            
  671.             break;
  672.             
  673.         case inZoomIn:
  674.         case inZoomOut:
  675.             if ( TrackBox( theWindow, event->where, part ) )
  676.             {
  677.                 CGrafPtr        port = GetWindowPort( theWindow );
  678.                 Rect            portRect;
  679.  
  680.                 SetPort( port );
  681.                 EraseRect( GetPortBounds( port, &portRect ) );
  682.                 ZoomWindow( theWindow, part, true );
  683.                 InvalWindowRect( theWindow, &portRect );
  684.             }
  685.             break;
  686.     }
  687. }
  688.  
  689. //———————————————————————————————————————————————————————————————————————————
  690. //    • HandleOSEvent
  691. //———————————————————————————————————————————————————————————————————————————
  692. //    Deal with OSEvents. These are messages that the process manager sends to
  693. //    us. Here, we deal with the suspend and resume message.
  694. //    
  695. static void
  696. HandleOSEvent( EventRecord *event )
  697. {
  698.     WindowPtr        window;
  699.  
  700.     switch( (event->message >> 24) & 0x00FF )
  701.     {
  702.         case suspendResumeMessage:
  703.         
  704.                 // In our SIZE resource, we say that we are MultiFinder aware.
  705.                 // This means that we take on the responsibility of activating
  706.                 // and deactivating our own windows on suspend/resume events. */
  707.  
  708.             gInBackground = (event->message & resumeFlag) == 0;
  709.  
  710.             window = FrontWindow();
  711.         
  712.             if ( window )
  713.             {
  714.                 BaseWindow*        wind;
  715.                 
  716.                 if ( GetObjectFromWindow( window, &wind ) )
  717.                 {
  718.                     if ( gInBackground )
  719.                         wind->Deactivate( *event );
  720.                     else
  721.                         wind->Activate( *event );
  722.                 }
  723.             }
  724.             break;
  725.             
  726.         case mouseMovedMessage:
  727.             break;
  728.     }
  729. }
  730.  
  731. //———————————————————————————————————————————————————————————————————————————
  732. //    • HandleUpdate
  733. //———————————————————————————————————————————————————————————————————————————
  734. //    This is called when an update event is received for a window. It calls
  735. //    DoUpdateWindow to draw the contents of an application window. As an
  736. //    efficiency measure that does not have to be followed, it calls the drawing
  737. //    routine only if the visRgn is nonempty. This will handle situations where
  738. //    calculations for drawing or drawing itself is very time consuming.
  739. //    
  740. static void
  741. HandleUpdate( EventRecord *event )
  742. {
  743.      WindowPtr            theWindow = (WindowPtr)event->message;
  744.      BaseWindow*        wind;
  745.      
  746.     if ( IsDialogWindow( theWindow ) )
  747.     {
  748.         DialogRef        dialog;
  749.         SInt16            itemHit;
  750.  
  751.         DialogSelect( event, &dialog, &itemHit );
  752.     }
  753.     else if ( GetObjectFromWindow( theWindow, &wind ) )
  754.     {
  755.         RgnHandle        region = NewRgn();
  756.         
  757.         if ( region )
  758.         {
  759.             GetPortVisibleRegion( GetWindowPort( theWindow ), region );
  760.  
  761.             if ( !EmptyRgn( region ) )
  762.             {
  763.                 SetPort( GetWindowPort( theWindow ) );
  764.                 wind->Update( *event );
  765.             }
  766.             DisposeRgn( region );
  767.         }
  768.     }
  769.     else
  770.     {
  771.         BeginUpdate( theWindow );
  772.         EndUpdate( theWindow );
  773.     }
  774. }
  775.  
  776. //———————————————————————————————————————————————————————————————————————————
  777. //    • AdjustMenus
  778. //———————————————————————————————————————————————————————————————————————————
  779. //    Enable and disable menus based on the currene state. The user can only 
  780. //    select enabled menu items. We set up all the menu items before calling
  781. //    MenuSelect or MenuKey, since these are the only times that a menu item can
  782. //    be selected. Note that MenuSelect is also the only time the user will see
  783. //    menu items. This approach to deciding what enable/disable state a menu
  784. //    item has has the advantage of concentrating all the decision making in one
  785. //    routine, as opposed to being spread throughout the application. Other
  786. //    application designs may take a different approach that is just as valid.
  787. //    
  788. static void
  789. AdjustMenus()
  790. {
  791.     WindowPtr        theWindow;
  792.     MenuHandle        menu;
  793.     BaseWindow*        wind;
  794.     
  795.     theWindow = FrontWindow();
  796.     
  797.     menu = GetMenuHandle( mFile );
  798.  
  799.     if ( theWindow )
  800.         EnableMenuItem( menu, iClose );
  801.     else
  802.         DisableMenuItem( menu, iClose );
  803.  
  804.     if ( theWindow && GetObjectFromWindow( theWindow, &wind ) )
  805.     {
  806.         wind->AdjustMenus();
  807.     }
  808. }
  809.  
  810. #if ENABLED_IN_CARBONLIB
  811. //
  812. // Simply displays an alert using StandardAlert that reminds the user about how to 
  813. // bring the titlebar back.  An exercise for the reader is implementing a system
  814. // whereby the menubar is hidden, but comes back temporarily when the mouse moves into the
  815. // menubar region.
  816. static void
  817. DoMenuAlert(void)
  818. {
  819.     AlertStdAlertParamRec myAlertRec = {false, false, nil, (unsigned char *)-1, nil, nil, kAlertStdAlertOKButton,0,kWindowDefaultPosition};
  820.     SInt16 ignoreHit;
  821.                                         
  822.     StandardAlert(kAlertPlainAlert, "\pAfter this dialog goes away, typing command-H will bring the menubar back", "\p", &myAlertRec, &ignoreHit);
  823.     HideMenuBar();
  824. }
  825.  
  826. static pascal Boolean
  827. TimeoutFilter(DialogPtr theDialog, EventRecord * /*theEvent*/, DialogItemIndex * /*itemHit*/)
  828. {
  829.     static Boolean firstTime = true;
  830.     OSStatus returnValue;
  831.     SInt16 whichButton;
  832.     UInt32 secondsToWait,secondsRemaining;
  833.     static UInt32 oldSecondsRemaining = 5;
  834.     
  835.     if (GetDialogTimeout(theDialog, &whichButton, &secondsToWait, &secondsRemaining) == dialogNoTimeoutErr)
  836.     // this is the first time through so set up the timeout
  837.         {
  838.              SetDialogTimeout(theDialog, kAlertStdAlertOKButton, 10); // 10 seconds, not ticks.
  839.              oldSecondsRemaining = 5;
  840.         }
  841.         
  842.     returnValue = GetDialogTimeout(theDialog, &whichButton, &secondsToWait, &secondsRemaining);
  843.  
  844.     if (returnValue == noErr)
  845.         {
  846.             if  (secondsRemaining != oldSecondsRemaining)  // don't redraw too often or it flickers
  847.                 {
  848.                     Str255 theString;
  849.                     DialogItemType ignoreType;
  850.                     Rect ignoreRect;
  851.                     Handle staticTextItem;
  852.                     
  853.                     GetDialogItem(theDialog, 3, &ignoreType, &staticTextItem, &ignoreRect);
  854.                     
  855.                     NumToString(secondsRemaining, theString);
  856.                     SetDialogItemText(staticTextItem, theString);
  857.                     oldSecondsRemaining = secondsRemaining; // save for next time through
  858.                     firstTime = false;
  859.                 }
  860.         }
  861.     
  862.     return(false);
  863. }
  864.  
  865.  
  866. //
  867. // DoDialogTimeouts simply brings up a modal dialog with a static text item in it.  The
  868. // filter proc above uses SetDialogTimeout and GetDialogTimeout to show how these 
  869. // routines can be used to have auto-dismissing dialogs.
  870. //
  871. static void
  872. DoDialogTimeouts(void)
  873. {
  874.     SInt16 ignoreHit;
  875.     ModalFilterUPP myModalFilter = NewModalFilterProc(TimeoutFilter);
  876.     DialogPtr myDialog = GetNewDialog(3000,nil,(WindowPtr) -1);
  877.     
  878.     if (!myDialog)
  879.         return;
  880.  
  881.     ModalDialog(myModalFilter,&ignoreHit);
  882.     
  883.     DisposeDialog(myDialog);
  884.     DisposeRoutineDescriptor(myModalFilter);
  885. }    
  886.  
  887. #endif
  888.  
  889.  
  890. //
  891. // DoCursorMenu is just a silly little way of showing how SetThemeCursor can be used..  It just takes
  892. // a cursor selector, which we're getting based upon which menu item was chosen.
  893. // 
  894.  
  895. #if ENABLED_IN_CARBONLIB
  896. static void 
  897. DoCursorMenu(short menuItem)
  898. {
  899.     gWhichCursor = menuItem - 1;
  900.     
  901.     if ((gWhichCursor >= kThemeArrowCursor) && (gWhichCursor <= kThemeResizeLeftRightCursor))
  902.         {
  903.             SetThemeCursor(gWhichCursor);
  904.             
  905.             if ((gWhichCursor == kThemeWatchCursor) || 
  906.                ((gWhichCursor >= kThemeCountingUpHandCursor) && (gWhichCursor <= kThemeSpinningCursor)))
  907.                {
  908.                        gAnimateCursor = true;
  909.                        gAnimationStep = 0; // reset
  910.                }
  911.         }
  912. }
  913. #endif        
  914.  
  915.         
  916. //———————————————————————————————————————————————————————————————————————————
  917. //    • HandleMenuCommand
  918. //———————————————————————————————————————————————————————————————————————————
  919. //    This is called when an item is chosen from the menu bar (after calling
  920. //    MenuSelect or MenuKey). It performs the right operation for each command.
  921. //    It tries to get the command ID of the menu item selected. If it can't, or
  922. //    the command is unknown, we pass it on to the front window, if any. We
  923. //    also special case the Apple menu items.
  924. //    
  925. static void
  926. HandleMenuCommand( long menuResult )
  927. {
  928.     short        menuID;
  929.     short        menuItem;
  930.     Str255        daName;
  931.     UInt32        command;
  932.     Boolean        handled;
  933.     OSErr        err;
  934.     WindowPtr    window;
  935.     
  936.     menuID = HiWrd( menuResult );
  937.     menuItem = LoWrd( menuResult );
  938.  
  939.     err = GetMenuItemCommandID( GetMenuHandle( menuID ), menuItem, &command );
  940.  
  941.     handled = false;
  942.     
  943.     if ( err || command == 0 )
  944.     {
  945.         if ( menuID == mApple )
  946.         {
  947.             GetMenuItemText( GetMenuHandle( mApple ), menuItem, daName );
  948. //            OpenDeskAcc( daName );
  949.             handled = true;
  950.         }
  951.     }
  952.     else
  953.     {
  954.         handled = true;
  955.         switch( command )
  956.         {
  957.             case kAboutSampleCmd:
  958.                 DoAboutBox();
  959.                 break;
  960.             
  961.             case kCloseCmd:
  962.                 if ( FrontWindow() )
  963.                     CloseAnyWindow( FrontWindow() );
  964.                 break;
  965.             
  966.             case kQuitCmd:
  967.                 gQuit = true;
  968.                 break;
  969.  
  970.             case kOpenFinderWindowCmd:
  971.                 new FinderWindow();
  972.                 break;
  973.                 
  974.             case kOpenDialogWindowCmd:
  975.                 new DialogWindow();
  976.                 break;
  977.             
  978.             case kOpenBevelDialogCmd:
  979.                 new BevelDialog();
  980.                 break;
  981.             
  982.             case kBevelImageAPICmd:
  983.                 new BevelImageAPIWindow();
  984.                 break;
  985.                 
  986.             case kCDEFTesterCmd:
  987.                 new CDEFTester();
  988.                 break;
  989.             
  990.             case kStandardAlertCmd:
  991.                 TestStandardAlert();
  992.                 break;
  993.             
  994.             case kLiveFeedbackCmd:
  995.                 new LiveFeedbackDialog();
  996.                 break;
  997.             
  998.             case kUtilityWindowCmd:
  999.                 new UtilityWindow();
  1000.                 break;
  1001.             
  1002.             case kSideUtilityWindowCmd:
  1003.                 new SideUtilityWindow();
  1004.                 break;
  1005.             
  1006.             case kMegaDialogCmd:
  1007.                 new MegaDialog();
  1008.                 break;
  1009.             
  1010.             case kAutoSizeCmd:
  1011.                 AutoSizeDialogTest();
  1012.                 break;
  1013.             
  1014.             case kVerticalZoomCmd:
  1015.                 window = GetNewWindow( 133, nil, (WindowPtr)-1L );
  1016.                 if ( window )
  1017.                 {
  1018.                     SetWindowKind( window, kVertZoomKind );
  1019.                     SetWindowPic( window, GetPicture( 133 ) );
  1020.                     SyncVertZoomRects( window );
  1021.                 }
  1022.                 break;
  1023.             
  1024.             case kHorizontalZoomCmd:
  1025.                 window = GetNewWindow( 134, nil, (WindowPtr)-1L );
  1026.                 if ( window )
  1027.                 {
  1028.                     SetWindowKind( window, kHorizZoomKind );
  1029.                     SetWindowPic( window, GetPicture( 134 ) );
  1030.                     SyncHorizZoomRects( window );
  1031.                 }
  1032.                 break;
  1033.             
  1034.             case kProxyPathDialogCmd:
  1035. #if ENABLED_IN_CARBONLIB
  1036.                 new ProxyDialog(2019);
  1037. #endif                
  1038.                 break;
  1039.             
  1040.             case kMenuDrawingTest:
  1041.                 DrawMenuStuff();
  1042.                 break;
  1043.             
  1044.             case kDumpHierarchy:
  1045.                 if ( FrontWindow() )
  1046.                 {
  1047.                     FSSpec        file;
  1048.                     
  1049.                     GetReportFileSpec( &file );
  1050.                     DumpControlHierarchy( FrontWindow(), &file );
  1051.                 }
  1052.                 break;
  1053.             
  1054.             case kHideMenu:
  1055. #if ENABLED_IN_CARBONLIB
  1056.                 if (IsMenuBarVisible())
  1057.                     DoMenuAlert();
  1058.                 else
  1059.                 ShowMenuBar();
  1060. #endif
  1061.                 break;
  1062.             
  1063.             case kDialogTimeouts:
  1064. #if ENABLED_IN_CARBONLIB
  1065.                 DoDialogTimeouts();
  1066. #endif                
  1067.                 break;
  1068.  
  1069.             default:
  1070.                 handled = false;
  1071.                 break;
  1072.                     
  1073.         }
  1074.  
  1075. #if ENABLED_IN_CARBONLIB        
  1076.         if (menuID == kMenuCursors)
  1077.         {
  1078.             DoCursorMenu(menuItem);
  1079.             handled = true;
  1080.         }
  1081. #endif
  1082.  
  1083.     }
  1084.     
  1085.     if ( !handled )
  1086.     {
  1087.         WindowPtr     frontWindow = FrontWindow();
  1088.         BaseWindow* wind;
  1089.         
  1090.         if ( frontWindow )
  1091.         {
  1092.             if ( GetObjectFromWindow( frontWindow, &wind ) )
  1093.             {
  1094.                 wind->HandleMenuSelection( menuID, menuItem );
  1095.             }
  1096.         }
  1097.     }
  1098.  
  1099.     HiliteMenu(0);
  1100. }
  1101.  
  1102. //———————————————————————————————————————————————————————————————————————————
  1103. //    • CloseAnyWindow
  1104. //———————————————————————————————————————————————————————————————————————————
  1105. //    Close the given window in a manner appropriate for that window. If the
  1106. //    window belongs to a DA, we call CloseDeakAcc. For dialogs, we simply hide
  1107. //    the window. If we had any document windows, we would probably call either
  1108. //    DisposeWindow or CloseWindow after disposing of any document data and/or
  1109. //    controls.
  1110. //    
  1111. static void
  1112. CloseAnyWindow( WindowPtr window )
  1113. {
  1114.     BaseWindow*        wind;
  1115.     
  1116.     if ( IsDAWindow( window ) )
  1117.     {
  1118.         // CloseDeskAcc( ((WindowPeek)window)->windowKind );
  1119.     }
  1120.     else if ( GetObjectFromWindow( window, &wind ) )
  1121.     {
  1122.         delete wind;
  1123.     }
  1124.     else
  1125.         DisposeWindow( window );
  1126. }
  1127.  
  1128. //———————————————————————————————————————————————————————————————————————————
  1129. //    • DeathAlert
  1130. //———————————————————————————————————————————————————————————————————————————
  1131. //    Display an alert that tell the user an err occurred, then exit the
  1132. //    program. This routine is used as an ultimate bail-out for serious errors
  1133. //    that prohibit the continuation of the application. The error number is
  1134. //    used to index an 'STR#' resource so that a relevant message can be
  1135. //    displayed.
  1136. //
  1137. static void
  1138. DeathAlert( short errNumber )
  1139. {
  1140.     short            itemHit;
  1141.     Str255            theMessage;
  1142.     Cursor            arrow;
  1143.     
  1144.     SetCursor( GetQDGlobalsArrow( &arrow ) );
  1145.     GetIndString( theMessage, kErrorStrings, errNumber );
  1146.     ParamText( theMessage, nil, nil, nil );
  1147.     itemHit = StopAlert( kAlertStartupError, nil );
  1148.     ExitToShell();
  1149. }
  1150.  
  1151. //———————————————————————————————————————————————————————————————————————————
  1152. //    • IsAppWindow
  1153. //———————————————————————————————————————————————————————————————————————————
  1154. //    Check to see if a window belongs to the application. If the window
  1155. //    pointer passed was NIL, then it could not be an application window.
  1156. //    WindowKinds that are negative belong to the system and windowKinds
  1157. //    less that userKind are reserved by Apple except for userKinds equal to
  1158. //    dialogKind, which means it's a dialog.
  1159. //    
  1160.  
  1161. static Boolean
  1162. IsAppWindow( WindowPtr window )
  1163. {
  1164.     short        windowKind;
  1165.     
  1166.     if ( window == nil )
  1167.         return false;
  1168.         
  1169.     windowKind = GetWindowKind( window );
  1170.     return( (windowKind >= userKind) || (windowKind == dialogKind) );
  1171. }
  1172.  
  1173. //———————————————————————————————————————————————————————————————————————————
  1174. //    • IsDAWindow
  1175. //———————————————————————————————————————————————————————————————————————————
  1176. //    Check to see if a window belongs to a desk accessory. It belongs to a DA
  1177. //    if the windowKind field of the window record is negative.
  1178. //    
  1179. static Boolean
  1180. IsDAWindow( WindowPtr window )
  1181. {
  1182.     if ( window == nil )
  1183.         return false;
  1184.  
  1185.     return( GetWindowKind( window ) < 0 );
  1186. }
  1187.  
  1188. //———————————————————————————————————————————————————————————————————————————
  1189. //    • IsDialogWindow
  1190. //———————————————————————————————————————————————————————————————————————————
  1191. //    Check to see if a window is a dialog window. We can determine this by
  1192. //    checking to see if the windowKind field is equal to dialogKind.
  1193. //
  1194. static Boolean
  1195. IsDialogWindow( WindowPtr window )
  1196. {
  1197.     if ( window == nil )
  1198.         return false;
  1199.  
  1200.     return( GetWindowKind( window ) == dialogKind );
  1201. }
  1202.  
  1203. //———————————————————————————————————————————————————————————————————————————
  1204. //    • GetObjectFromWindow
  1205. //———————————————————————————————————————————————————————————————————————————
  1206. //    Gets the object pointer from the refCon of the given window if the kind
  1207. //    is right. If the kind is wrong, or the refCon is null, we return false.
  1208. //
  1209. static Boolean
  1210. GetObjectFromWindow( WindowPtr window, BaseWindow** wind )
  1211. {
  1212.     SInt32        test;
  1213.     
  1214.     if ( GetWindowKind( window ) != kObjectWindowKind )
  1215.         return false;
  1216.         
  1217.     test = GetWRefCon( window );
  1218.     if ( test == nil ) return false;
  1219.     
  1220.     *wind = (BaseWindow*)test;
  1221.  
  1222.     return true;
  1223. }
  1224.  
  1225. //———————————————————————————————————————————————————————————————————————————
  1226. //    • SetUpFontMenu
  1227. //———————————————————————————————————————————————————————————————————————————
  1228. //    This routine calls AddResMenu to add all fonts to our font menu. We then
  1229. //    go thru each item and set the item's font to the actual font!
  1230. //
  1231. static void
  1232. SetUpFontMenu()
  1233. {
  1234.     SInt16            i, numItems;
  1235.     Str255            fontName;
  1236.     SInt16            fontNum;
  1237.     
  1238.     gFontMenu = GetMenu( kMenuFonts );
  1239.     if ( gFontMenu == nil ) return;
  1240.     
  1241.     AppendResMenu( gFontMenu, 'FONT' );
  1242.     
  1243.     numItems = CountMItems( gFontMenu );
  1244.     for ( i = 1; i <= numItems; i++ )
  1245.     {
  1246.         GetMenuItemText( gFontMenu, i, fontName );
  1247.         GetFNum( fontName, &fontNum );
  1248.         SetMenuItemFontID( gFontMenu, i, fontNum );
  1249.     }    
  1250.     InsertMenu(gFontMenu,0);
  1251.  
  1252.     DisableMenuItem(gFontMenu,0);
  1253. }
  1254.  
  1255. //———————————————————————————————————————————————————————————————————————————
  1256. //    • SetUpModifiersMenu
  1257. //———————————————————————————————————————————————————————————————————————————
  1258. //    This routine programmatically sets the modifiers for our modifier menu.
  1259. //
  1260. static void
  1261. SetUpModifiersMenu()
  1262. {
  1263.     MenuHandle        menu;
  1264.     Handle            suite;
  1265.     OSErr            err;
  1266.     
  1267.     menu = GetMenuHandle( kMenuModifiers );
  1268.     if ( menu == nil ) return;
  1269.  
  1270.     SetMenuItemModifiers( menu, kShiftModifierItem, kMenuShiftModifier );    
  1271.     SetMenuItemModifiers( menu, kShiftOptionModifierItem, kMenuShiftModifier + kMenuOptionModifier );    
  1272.     SetMenuItemModifiers( menu, kShiftOptCntlModifierItem, kMenuShiftModifier + kMenuOptionModifier + kMenuControlModifier );    
  1273.  
  1274.     SetItemCmd( menu, kCommandDeleteItem, 0x08 ); // delete key
  1275.  
  1276.     SetMenuItemKeyGlyph( menu, kCommandDeleteItem, 0x17 ); // delete key glyph in font
  1277.     
  1278.     err = GetIconSuite( &suite, -3997, kSelectorAllAvailableData );
  1279.     if ( err == noErr )
  1280.         SetMenuItemIconHandle( menu, kIconSuiteItem, kMenuIconSuiteType, suite );
  1281.  
  1282.     // The rest of the items in this large menu show the various special characters that can be used in menus.
  1283.     // They are set up when the menu is created by the data in the corresponding xmnu resource
  1284. }
  1285.  
  1286. //———————————————————————————————————————————————————————————————————————————
  1287. //    • DoAboutBox
  1288. //———————————————————————————————————————————————————————————————————————————
  1289. //    Puts up our about box dialog. Note that we use a dialog and NOT an alert.
  1290. //    This is a good practice to get into, since alerts are now colored differently
  1291. //    to distiguish them from normal dialogs.
  1292. //
  1293. static void
  1294. DoAboutBox()
  1295. {
  1296.     DialogPtr        dialog;
  1297.     SInt16            itemHit;
  1298.     
  1299.     dialog = GetNewDialog( kAboutBoxDialogID, nil, (WindowPtr)-1L );
  1300.     if ( dialog == nil ) return;
  1301.  
  1302.     SetDialogDefaultItem( dialog, 4 );    
  1303.     ModalDialog( nil, &itemHit );
  1304.     
  1305.     DisposeDialog( dialog );
  1306. }
  1307.  
  1308. //————————————————————————————————————————————————————————————————————————————
  1309. //    • AutoSizeDialogTest
  1310. //————————————————————————————————————————————————————————————————————————————
  1311. //    Simple little routine to demonstrate the AutoSizeDialog API
  1312. //
  1313. static void
  1314. AutoSizeDialogTest()
  1315. {
  1316.     DialogPtr        dialog;
  1317.     SInt16            itemHit = 0;
  1318.     
  1319.     dialog = GetNewDialog( 4000, nil, (WindowPtr)-1L );
  1320.     if ( dialog == nil ) return;
  1321.     
  1322.     SetDialogDefaultItem( dialog, 2 );
  1323.     
  1324.     while ( itemHit != 2 )
  1325.     {
  1326.         ModalDialog( nil, &itemHit );
  1327.  
  1328.         if ( itemHit == 3 )
  1329.             AutoSizeDialog( dialog );
  1330.     }
  1331.     DisposeDialog( dialog );
  1332. }
  1333.  
  1334. //————————————————————————————————————————————————————————————————————————————
  1335. //    • SyncVertZoomRects
  1336. //————————————————————————————————————————————————————————————————————————————
  1337. //    Sets up the standard and user rectangles for our vertical zooming window.
  1338. //
  1339. static void
  1340. SyncVertZoomRects( WindowPtr window )
  1341. {
  1342.     Rect        bounds;
  1343.     CGrafPtr    port;
  1344.     
  1345.     port = GetWindowPort( window );
  1346.  
  1347.     SetPort( port );
  1348.     GetPortBounds( port, &bounds );
  1349.     
  1350.     if ( (bounds.bottom - bounds.top) < 200 )
  1351.         bounds.bottom = bounds.top + 200;
  1352.         
  1353.     LocalToGlobal( &topLeft( bounds ) );
  1354.     LocalToGlobal( &botRight( bounds ) );
  1355.     
  1356.     SetWindowStandardState( window, &bounds );
  1357.     
  1358.     bounds.bottom = bounds.top + 60;
  1359.     SetWindowUserState( window, &bounds );
  1360. }
  1361.  
  1362. //————————————————————————————————————————————————————————————————————————————
  1363. //    • SyncHorizZoomRects
  1364. //————————————————————————————————————————————————————————————————————————————
  1365. //    Sets up the standard and user rectangles for our horizontal zooming window.
  1366. //
  1367. static void
  1368. SyncHorizZoomRects( WindowPtr window )
  1369. {
  1370.     Rect        bounds;
  1371.     CGrafPtr    port;
  1372.  
  1373.     port = GetWindowPort( window );
  1374.  
  1375.     SetPort( port );
  1376.     GetPortBounds( port, &bounds );
  1377.  
  1378.     if ( (bounds.right - bounds.left) < 240 )
  1379.         bounds.right = bounds.left + 240;
  1380.         
  1381.     LocalToGlobal( &topLeft( bounds ) );
  1382.     LocalToGlobal( &botRight( bounds ) );
  1383.     
  1384.     SetWindowStandardState( window, &bounds );
  1385.     
  1386.     bounds.right = bounds.left + 60;
  1387.     SetWindowUserState( window, &bounds );
  1388. }
  1389.  
  1390. //————————————————————————————————————————————————————————————————————————————
  1391. //    • GetReportFileSpec
  1392. //————————————————————————————————————————————————————————————————————————————
  1393. //    Returns our file spec for dumping pane information.
  1394. //
  1395. static OSErr
  1396. GetReportFileSpec( FSSpecPtr file )
  1397. {
  1398.     FCBPBRec    pb;
  1399.     Str255        ourName;
  1400.     OSErr        err;
  1401.     
  1402.     pb.ioVRefNum    = -1;
  1403.     pb.ioFCBIndx    = 0;
  1404.     pb.ioNamePtr    = ourName;
  1405.     pb.ioRefNum        = CurResFile();
  1406.     
  1407.     err = PBGetFCBInfoSync( &pb );
  1408.     if ( err ) return err;
  1409.     
  1410.     err = FSMakeFSSpec( pb.ioFCBVRefNum, pb.ioFCBParID, "\pPane Dump", file );
  1411.     return err;
  1412. }
  1413.  
  1414. //————————————————————————————————————————————————————————————————————————————
  1415. //    • MyControlCNTLToCollectionProc
  1416. //————————————————————————————————————————————————————————————————————————————
  1417. //    All controls are now created through a new API (CreateNewCustomControl)
  1418. //    which does not take explicit value, min, max, refCon, or other parameters.
  1419. //    Instead, it takes a Collection which can have all of that information
  1420. //    along with any special info which is unique to each Control Definition.
  1421. //    Unfortunately, calls to NewControl and GetNewControl only have access to
  1422. //    the basic value, min, max information. Because those pieces of information
  1423. //    might be overloaded to have a special meaning for our Control Definition,
  1424. //    the Control Manager needs to know how to translate that data into the right
  1425. //    tagged Collection data. We have registered this routine to do the
  1426. //    translation for our custom Control Definition.
  1427. //
  1428. pascal OSStatus MyControlCNTLToCollectionProc( const Rect * bounds, SInt16 value,
  1429.     Boolean visible, SInt16 max, SInt16 min, SInt16 procID, SInt32 refCon,
  1430.     ConstStr255Param title, Collection collection)
  1431. {
  1432. #pragma unused( procID )
  1433.  
  1434.     OSStatus        err = noErr;
  1435.     SInt32        value32 = value;
  1436.     SInt32        max32 = max;
  1437.     SInt32        min32 = min;
  1438.  
  1439.     // The value, min, etc. do not get overloaded into special meanings for us,
  1440.     // so we can simply add each one to the collection with the standard Control
  1441.     // Collection Tags. The Control Manager will recognize these standard tags
  1442.     // and will give their values to the control instance.
  1443.  
  1444.     err = AddCollectionItem( collection, kControlCollectionTagBounds, 0,
  1445.         sizeof( Rect ), (void*)bounds );
  1446.     if ( err != noErr ) goto CantAddCollectionItem;
  1447.  
  1448.     err = AddCollectionItem( collection, kControlCollectionTagValue, 0,
  1449.         sizeof( SInt32 ), &value32 );
  1450.     if ( err != noErr ) goto CantAddCollectionItem;
  1451.  
  1452.     err = AddCollectionItem( collection, kControlCollectionTagVisibility, 0,
  1453.         sizeof( Boolean ), &visible );
  1454.     if ( err != noErr ) goto CantAddCollectionItem;
  1455.  
  1456.     err = AddCollectionItem( collection, kControlCollectionTagMaximum, 0,
  1457.         sizeof( SInt32 ), &max32 );
  1458.     if ( err != noErr ) goto CantAddCollectionItem;
  1459.  
  1460.     err = AddCollectionItem( collection, kControlCollectionTagMinimum, 0,
  1461.         sizeof( SInt32 ), &min32 );
  1462.     if ( err != noErr ) goto CantAddCollectionItem;
  1463.  
  1464.     err = AddCollectionItem( collection, kControlCollectionTagRefCon, 0,
  1465.         sizeof( SInt32 ), &refCon );
  1466.     if ( err != noErr ) goto CantAddCollectionItem;
  1467.  
  1468.     err = AddCollectionItem( collection, kControlCollectionTagTitle, 0,
  1469.         title[0], (void*)&title[1] );
  1470.     if ( err != noErr ) goto CantAddCollectionItem;
  1471.  
  1472. CantAddCollectionItem:
  1473.     
  1474.     return err;
  1475. }
  1476.  
  1477. //————————————————————————————————————————————————————————————————————————————
  1478. //    • MyControlDefProc
  1479. //————————————————————————————————————————————————————————————————————————————
  1480. //    The entrypoint for our custom Control Definition.
  1481. //    We can and must do all of the stuff that we would have done within a
  1482. //    'CDEF' resource.
  1483. //
  1484. //    This particular Control Definition simply draws its title within the
  1485. //    control's bounds.
  1486. //
  1487. pascal SInt32 MyControlDefProc(    SInt16 varCode, ControlHandle theControl,
  1488.     ControlDefProcMessage message, SInt32 param)
  1489. {
  1490. #pragma unused( varCode )
  1491.  
  1492.     SInt32                 result = 0;
  1493.     Rect                bounds;
  1494.     Str255                title;
  1495.     GrafPtr                currentPort;
  1496.     ThemeDrawingState    state;
  1497.     SInt16                savedFont;
  1498.     Style                savedFace;
  1499.     SInt16                savedMode;
  1500.     SInt16                savedSize;
  1501.     RgnHandle            region;
  1502.  
  1503.     GetControlBounds( theControl, &bounds );
  1504.     GetControlTitle( theControl, title );
  1505.  
  1506.     switch ( message ) {
  1507.         case drawCntl:
  1508.             // prepare to draw in the current port
  1509.             GetPort( ¤tPort );
  1510.             savedFont = GetPortTextFont( currentPort );
  1511.             savedFace = GetPortTextFace( currentPort );
  1512.             savedMode = GetPortTextMode( currentPort );
  1513.             savedSize = GetPortTextSize( currentPort );
  1514.             GetThemeDrawingState( &state );
  1515.             NormalizeThemeDrawingState();
  1516.             UseThemeFont( kThemeSystemFont, smSystemScript );
  1517.  
  1518.             // just draw our title within our bounding box
  1519.             TETextBox( &title[1], title[0], &bounds, teFlushDefault );
  1520.  
  1521.             // restore what we did to the port
  1522.             SetThemeDrawingState( state, true );
  1523.             TextFont( savedFont );
  1524.             TextFace( savedFace );
  1525.             TextMode( savedMode );
  1526.             TextSize( savedSize );
  1527.             break;
  1528.  
  1529.         case testCntl:
  1530.             // we are display only, so we don't track
  1531.             result = kControlNoPart;
  1532.             break;
  1533.  
  1534.         case initCntl:
  1535.             // we don't do any special work during initialization
  1536.             // and we return noErr as an indication that initialization
  1537.             // was successful.
  1538.             result = noErr;
  1539.             break;
  1540.  
  1541.         case dispCntl:
  1542.             // we don't have to do any work
  1543.             break;
  1544.  
  1545.         case calcCntlRgn:
  1546.             // this Control Definition is as big as its bounds
  1547.             region = (RgnHandle)param;
  1548.             RectRgn( region, &bounds );
  1549.             break;
  1550.  
  1551.         case kControlMsgGetFeatures:
  1552.             // we have no features
  1553.             result = 0;
  1554.             break;
  1555.  
  1556.         case kControlMsgTestNewMsgSupport:
  1557.             // we support the new messages, so return
  1558.             // the appropriate value
  1559.             result = kControlSupportsNewMessages;
  1560.             break;
  1561.  
  1562.         default:
  1563.             break;
  1564.     }
  1565.  
  1566.     return result;
  1567. }
  1568.  
  1569.